package com.i360day.invoker.registry;

import com.i360day.invoker.annotation.RemoteClient;
import com.i360day.invoker.annotation.RemoteModule;
import com.i360day.invoker.annotation.RemoteScan;
import com.i360day.invoker.common.ClassUtils;
import com.i360day.invoker.common.RemoteModuleUtils;
import com.i360day.invoker.common.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/**
 * <p> @description:     <p>
 * <p>
 * <p> @author: 胡.青牛   <p>
 * <p>
 * <p> @date: 2019/4/30 0030  13:01
 **/
class RemoteScanImportBeanDefinitionRegistrar extends AbstractRemoteScanAnnotationParser {

    private Logger logger = LoggerFactory.getLogger(RemoteScanImportBeanDefinitionRegistrar.class);

    public RemoteScanImportBeanDefinitionRegistrar(ResourceLoader resourceLoader, Environment environment) {
        super(resourceLoader, environment);
    }

    /**
     * <p> @Description: 扫描包   <p>
     *
     * <p> @author: 胡.青牛   <p>
     *
     * <p> @Date:   2019/5/11 0011 16:45   <p>
     *
     * <p> @param null     <p>
     *
     * <p> @return:      <p>
     **/
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //获取扫描包
        Map<String, Object> remoteScanAttrMap = importingClassMetadata.getAnnotationAttributes(RemoteScan.class.getName(), true);
        //拿到扫描包路径
        Object basePackages = remoteScanAttrMap.get("basePackages");
        String[] packages = StringUtils.isPackage(basePackages) ? getPackageName(importingClassMetadata) : (String[]) basePackages;
        Assert.isTrue(!StringUtils.isPackage(packages), "@RemoteScan attribute basePackages is required");
        //找到包下的class并注册bean
        findPackageClassAndRegistryBean(registry, packages);
    }

    /**
     * <p> @Description: 获取指定包下的class，分析注册bean   <p>
     *
     * <p> @author: 胡.青牛   <p>
     *
     * <p> @Date:   2019/5/11 0011 16:45   <p>
     *
     * <p> @param null     <p>
     *
     * <p> @return:      <p>
     **/
    protected void findPackageClassAndRegistryBean(BeanDefinitionRegistry registry, String... packages) {
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(getResourceLoader());
        scanner.addIncludeFilter(new AnnotationTypeFilter(RemoteClient.class));
        //
        Arrays.asList(packages).forEach(aPackage -> {
            Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(aPackage);
            //
            beanDefinitions.stream()
                    .filter(beanDefinition -> beanDefinition instanceof AnnotatedBeanDefinition)
                    .forEach(beanDefinition -> {
                        registerInterfaceBean(registry, ((AnnotatedBeanDefinition) beanDefinition).getMetadata());
                    });
        });
    }

    /**
     * <p> @author liju.z <p>
     *
     * <p> @Description 获取到RemoteService，将相应的bean进行创建 <p>
     *
     * <p> @Date  2022-08-13 15:00 <p>
     *
     * <p> @Param registry <p>
     * <p> @Param beanDefinition <p>
     **/
    protected synchronized void registerInterfaceBean(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata) {
        // verify annotated class is an interface
        Assert.isTrue(annotationMetadata.isInterface(), "@RemoteClient can only be specified on an interface");
        Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(RemoteClient.class.getCanonicalName());
        Class<?> clientProxyClass = ClassUtils.getTargetClass(attributes.get("clientProxyClass"));
        Class<?> serverProxyClass = ClassUtils.getTargetClass(attributes.get("serverProxyClass"));
        Class<?> interfaceClazz = ClassUtils.getClass(annotationMetadata.getClassName());
        //获取父类配置，始终优先读取父类
        RemoteModule remoteModule = RemoteModuleUtils.getRemoteModule(interfaceClazz);
        Assert.notNull(remoteModule, String.format("%s Not included RemoteModule/RemoteClient annotation", interfaceClazz));
        attributes.putAll(AnnotationUtils.getAnnotationAttributes(remoteModule, true));
        //注册bean
        registerRemoteBean(registry, interfaceClazz, attributes, clientProxyClass, serverProxyClass);
    }
}
